package be.jas.mvc.base.model.fam;

import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: jasmien
 * Date: 11/07/13
 * Time: 14:00
 * To change this template use File | Settings | File Templates.
 */
public class FamFeature extends AbstractReasoner {

    private static int next_index = 1;

    private static int getNextIndex(){
        return next_index++;
    }

    private boolean value;

    private String description;

    private List<FamComposition> compositions;

    //cardinality
    private int min;
    private int max;
    private boolean concrete;

    private Integer index;

    private List<FamFeature> excludes;
    private List<FamFeature> requires;
    private List<FamFeature> same;
    private List<FamFeature> incompatible;
    private List<FamFeature> uses;
    private List<FamFeature> includes;
    private List<FamFeature> impacts;
    private List<FamFeature> extendsFeatures;

    public void addExclude(FamFeature feature){
        this.excludes.add(feature);
    }

    public void addRequires(FamFeature feature){
        this.requires.add(feature);
    }

    public void addSame(FamFeature feature){
        this.same.add(feature);
    }

    public void addIncompatible(FamFeature feature){
        this.incompatible.add(feature);
    }

    public void addUses(FamFeature feature){
        this.uses.add(feature);
    }

    public void addIncludes(FamFeature feature){
        this.includes.add(feature);
    }

    public void addImpacts(FamFeature feature){
        this.impacts.add(feature);
    }

    public void addExtends(FamFeature feature){
        this.extendsFeatures.add(feature);
    }

    public Integer getIndex() {
        return index;
    }

    public FamFeature(String id, String description) {
        super(id, description);
        compositions = new ArrayList<FamComposition>();
        this.min = 1;
        this.max = 1;
        this.concrete = false;
        this.excludes = new ArrayList<FamFeature>();
        this.requires = new ArrayList<FamFeature>();
        this.same = new ArrayList<FamFeature>();
        this.incompatible = new ArrayList<FamFeature>();
        this.uses = new ArrayList<FamFeature>();
        this.includes = new ArrayList<FamFeature>();
        this.impacts = new ArrayList<FamFeature>();
        this.extendsFeatures = new ArrayList<FamFeature>();
        this.index = getNextIndex();
    }

    public boolean isConcrete() {
        return concrete;
    }

    public void setConcrete(boolean concrete) {
        this.concrete = concrete;
    }

    public void setCardinality(int min, int max){
        this.min = min;
        this.max = max;
    }

    public FamComposition addMandatoryComposition(){
        FamComposition composition = new FamComposition(true);
        compositions.add(composition);
        return composition;
    }

    public FamComposition addOptionalComposition(){
        FamComposition composition = new FamComposition(false);
        compositions.add(composition);
        return composition;
    }

    public List<FamComposition> getCompositions() {
        return compositions;
    }

    public void setCompositions(List<FamComposition> compositions) {
        this.compositions = compositions;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String toString(String prefix){
        String ret = "\n" + prefix + "Feature " + super.toString(prefix + "\t") + "\n";
        ret += prefix +"\n\t\ttype: " + (concrete ? "concrete" : "abstract") + "\n";
        ret += prefix +"\tcardinality: " + min + "/" + max + "\n";
        ret += prefix +"\tCompositions:\n";
        for(FamComposition entry : compositions){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tExcludes:\n";
        for(FamFeature entry : excludes){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tRequires:\n";
        for(FamFeature entry : requires){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tSame:\n";
        for(FamFeature entry : same){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tIncompatible:\n";
        for(FamFeature entry : incompatible){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tUses:\n";
        for(FamFeature entry : uses){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tIncludes:\n";
        for(FamFeature entry : includes){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tImpacts:\n";
        for(FamFeature entry : impacts){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        ret += prefix +"\tExtends:\n";
        for(FamFeature entry : extendsFeatures){
            ret += entry.toString(prefix + "\t\t") + "\n";
        }
        return ret;
    }

    public int getMin() {
        return min;
    }

    public int getMax() {
        return max;
    }

    public List<FamFeature> getExcludes() {
        return excludes;
    }

    public List<FamFeature> getRequires() {
        return requires;
    }

    public List<FamFeature> getSame() {
        return same;
    }

    public List<FamFeature> getIncompatible() {
        return incompatible;
    }

    public List<FamFeature> getUses() {
        return uses;
    }

    public List<FamFeature> getIncludes() {
        return includes;
    }

    public List<FamFeature> getImpacts() {
        return impacts;
    }

    public List<FamFeature> getExtendsFeatures() {
        return extendsFeatures;
    }

    public boolean isValue() {
        return value;
    }

    public void setValue(boolean value) {
        this.value = value;
    }

    @Override
    public Collection<FamFeature> getAllFeatures() {
        //TODO is dit nodig?
        List<FamFeature> allFeatures = new ArrayList<FamFeature>(super.getAllFeatures());
        for(FamComposition composition : compositions){
            allFeatures.addAll(composition.getAllFeatures());
        }
        return allFeatures;
    }

    public List<FamFeature> getAllFeaturesWithConstraints(){
        List<FamFeature> allFeatures = new ArrayList<FamFeature>(getAllFeatures());
        for(FamFeature feature : requires){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : excludes){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : uses){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : incompatible){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : impacts){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : includes){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : extendsFeatures){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        for(FamFeature feature : same){
            allFeatures.add(feature);
            allFeatures.addAll(feature.getAllFeatures()); //TODO is dit wel nodig?
        }
        return allFeatures;
    }
}
